
#include "area.h"
#include "avatar.h"
#include "commands-redit.h"
#include "commandTable.h"
#include "commandTable-default.h"
#include "display.h"
#include "handler.h"
#include "room.h"
#include "symphony.h"
#include "terrainTable.h"
#include "world.h"

/*
RCmd::RCmd( void ) {
  name( "" );
  return;
}

bool RCmd::execute( Creature* creature, const std::string& args ) {

  return true;
}
*/

RCmdCreate::RCmdCreate( void ) {
  name( "create" );
  level( BUILDER );
  syntax( "syntax: create [vnum]" );
  return;
}

bool RCmdCreate::execute( Creature* creature, const std::string& args ) {
  unsigned long vnum = 0;
  Area* area = NULL;
  Room* room = NULL;

  if ( args.empty() ) {
    /* vnum wasn't specified; use the lowest open vnum in the area */
    for ( unsigned long u = creature->room()->area()->low(); u <= creature->room()->area()->high(); ++u ) {
      if ( World::Instance().findRoom( u ) == NULL ) {
        // Found an empty vnum; use it
        vnum = u;
        break;
      }
    }
    if ( !vnum ) {
      creature->send( "No empty vnum could be found for the current area." );
      return false;
    }
  } else {
    /* vnum explicitly specifed; use that value */
    vnum = estring(args);
  }

  // Make sure the vnum exists...
  if ( ( area = World::Instance().lookup( vnum ) ) == NULL ) {
    creature->send( "That vnum doesn't exist." );
    return false;
  }
  // Check permissions...
  if ( !World::Instance().hasPermission( area, (Avatar*)creature ) ) {
    creature->send( "You don't have permissions to that vnum." );
    return false;
  }
  // Make sure the room doesn't exist...
  if ( World::Instance().findRoom( vnum ) != NULL ) {
    creature->send( "That room already exists." );
    return false;
  }
  // Everything looks clear; create the room...
  room = new Room( vnum, area );
  creature->pointer( room );
  creature->send( "You've created room %lu.\n", room->vnum() );

  return true;
}

RCmdDelete::RCmdDelete( void ) {
  name( "delete" );
  level( BUILDER );
  syntax( "syntax: delete delete" );
  return;
}

bool RCmdDelete::execute( Creature* creature, const std::string& args ) {
  Area* area = NULL;
  Room* room = creature->room();
  unsigned long vnum = room->vnum();

  if ( args != "delete" ) {
    creature->send( syntax() );
    return false;
  }

  if ( ( area = World::Instance().lookup( vnum ) ) == NULL ) {
    creature->send( "Error establishing vnum-area association." );
    return false;
  }

  if ( !room->destroy() ) {
    creature->send( "Failed to destroy room." );
    return false;
  }

  // Success!
  creature->send( "\nRoom %lu deleted.\n", vnum );

  return true;
}

RCmdDescription::RCmdDescription( void ) {
  name( "description" );
  return;
}

bool RCmdDescription::execute( Creature* creature, const std::string& args ) {
  Handler* h = new TeditHandler( creature );
  h->getState()["vector"] = (void*)(new std::vector<std::string>(Display::refactor(creature->room()->description())));
  h->getState()["name"] = (void*)(new std::string("Room Description"));
  h->getState()["pointer"] = (void*)creature->room()->descriptionp();
  creature->pushHandler( h );
  return true;
}

RCmdDig::RCmdDig( void ) {
  name( "dig" );
  level( BUILDER );
  syntax( "syntax: dig <direction> [vnum]" );
  return;
}

bool RCmdDig::execute( Creature* creature, const std::string& args ) {
  std::vector<std::string> pieces = Regex::split( args, 2 );
  Room* room = NULL;
  char buffer[MAX_BUFFER];
  RCmdCreate create;
  RCmdLink link;
  CmdGoto go;

  if ( pieces.empty() || pieces.size() > 2 ) {
    creature->send( syntax() );
    return false;
  }

  // Create the new room...
  if ( pieces.size() == 1 ) {
    // The vnum is being implied, so we have to do a little dance to get things to work right...
    if ( create.execute( creature, "" ) ) {
      room = (Room*)creature->pointer();
      sprintf( buffer, "%s %lu", pieces[0].c_str(), room->vnum() );
      if ( link.execute( creature, buffer ) ) {
        go.execute( creature, estring(room->vnum()) );
      }
    }
  } else if ( pieces.size() == 2 ) {
    // Easy case - an explicit vnum...
    if ( create.execute( creature, pieces[1] ) ) {
      if ( link.execute( creature, args ) ) {
        go.execute( creature, pieces[1] );
      }
    }
  }

  return true;
}

RCmdExitflag::RCmdExitflag( void ) {
  name( "exitflag" );
  level( BUILDER );
  syntax( "syntax: exitflag <direction> add <type1> [<type2> <type3>...]\n        exitflag <direction> remove <type1> [<type2> <type3>...]\n\nValid flags: closeable closed lockable locked hidden" );
  return;
}

bool RCmdExitflag::execute( Creature* creature, const std::string& args ) {
  std::vector<std::string> pieces = Regex::split( args, 2 );
  std::vector<std::string> flags;
  Exit* exit = NULL;
  unsigned short direction = 0;
  bool value = false;

  if ( pieces.size() < 3 ) {
    creature->send( syntax() );
    return false;
  }

  flags = Regex::explode( " ", pieces[2], true );
  direction = Exit::string2dir( pieces[0] );

  if ( ( exit = creature->room()->exit( direction ) ) == NULL ) {
    creature->send( "There is no exit in that direction." );
    return false;
  }

  if ( Regex::strPrefix( pieces[1], "add" ) ) {
    value = true;
  } else if ( Regex::strPrefix( pieces[1], "remove" ) ) {
    value = false;
  } else {
    creature->send( syntax() );
    return false;
  }

  for ( std::vector<std::string>::iterator it = flags.begin(); it != flags.end(); ++it ) {
    exit->flag( Exit::getFlagType( *it ), value );
  }

  creature->send( "%s flags are now: %s", Exit::name( direction ), exit->listFlags().c_str() );
  return true;
}

RCmdFlag::RCmdFlag( void ) {
  name( "flag" );
  level( BUILDER );
  syntax( "syntax: flag add <type1> [<type2> <type3>...]\n        flag remove <type1> [<type2> <type3>...]\n\nValid flags: nomap nogate" );
  return;
}

bool RCmdFlag::execute( Creature* creature, const std::string& args ) {
  std::vector<std::string> pieces = Regex::split( args, 1 );
  std::vector<std::string> flags;
  bool value = false;

  if ( pieces.size() < 2 ) {
    creature->send( syntax() );
    return false;
  }

  flags = Regex::explode( " ", pieces[1], true );

  if ( Regex::strPrefix( pieces[0], "add" ) ) {
    value = true;
  } else if ( Regex::strPrefix( pieces[0], "remove" ) ) {
    value = false;
  } else {
    creature->send( syntax() );
    return false;
  }

  for ( std::vector<std::string>::iterator it = flags.begin(); it != flags.end(); ++it ) {
    creature->room()->flag( Room::getFlagType( *it ), value );
  }

  creature->send( "Room flags are now: %s", creature->room()->listFlags().c_str() );
  return true;
}

RCmdInformation::RCmdInformation( void ) {
  name( "information" );
  level( BUILDER );
  return;
}

bool RCmdInformation::execute( Creature* creature, const std::string& args ) {
  std::string output;
  char buffer[MAX_BUFFER];
  char exit_buf[MAX_BUFFER];
  Room* room = creature->room();

  output.append( " --== {Yroom data{x ==--\n" );
  sprintf( buffer, "area..... {y%s{x\n\
vnum..... {y%lu{x\n\
name..... {y%s{x\n\
flags.... {y%s{x\n\
terrain.. {y%s{x\n\
smell.... {y%s{x\n\
sound.... {y%s{x\n\n\
",  room->area()->name().c_str(), room->vnum(), room->name().c_str(), room->listFlags().c_str(),
    room->terrain()->name().c_str(), room->smell().c_str(), room->sound().c_str() );
  output.append( buffer );

  output.append( " --== {Yexit data{x ==--\n" );
  for ( register unsigned short u = 0; u < 6; ++u ) {
    if ( room->exit( u ) ) {
      sprintf( exit_buf, "{y%s{x to room {y%lu{x ({y%s{x)\n", Exit::name( u ), room->exit( u )->target()->vnum(), room->exit( u )->target()->name().c_str() );
      output.append( exit_buf );
      sprintf( exit_buf, "  Flags: {y%s{x\n", room->exit( u )->listFlags().c_str() );
      output.append( exit_buf );
      if ( room->exit( u )->key() ) {
        sprintf( exit_buf, "  Key: {y%lu{x\n", room->exit( u )->key() );
        output.append( exit_buf );
      }
    }
  }

  creature->send( output );
  return true;
}

RCmdKey::RCmdKey( void ) {
  name( "key" );
  level( BUILDER );
  syntax( "syntax: key <direction> <key_vnum>" );
  return;
}

bool RCmdKey::execute( Creature* creature, const std::string& args ) {
  std::vector<std::string> pieces = Regex::split( args );
  Exit* exit = NULL;
  Exit* other = NULL;
  unsigned long vnum = 0;

  if ( pieces.size() != 2 ) {
    creature->send( syntax() );
    return false;
  }

  if ( ( exit = creature->room()->exit( pieces[0] ) ) == NULL ) {
    creature->send( "There is no exit in that direction." );
    return false;
  }

  vnum = estring(pieces[1]);

  exit->key( vnum );
  if ( ( other = exit->target()->exit( Exit::inverse( exit->direction() ) ) ) != NULL ) {
    other->key( vnum );
  }

  creature->send( "%s exit's key set to object %lu.\n", Exit::name( exit->direction() ), exit->key() );
  return true;
}

RCmdLink::RCmdLink( void ) {
  name( "link" );
  level( BUILDER );
  syntax( "syntax: link <direction> <vnum>" );
  return;
}

bool RCmdLink::execute( Creature* creature, const std::string& args ) {
  std::vector<std::string> pieces = Regex::split( args, 2 );
  unsigned short in_dir = 0; // Direction we're linking out from
  unsigned short to_dir = 0; // Direction we'll be entering the target room from
  Room* in = NULL;  // Current room
  Room* to = NULL;  // Target room

  if ( pieces.size() != 2 ) {
    creature->send( syntax() );
    return false;
  }

  in = creature->room();
  if ( ( in_dir = Exit::string2dir(pieces[0]) ) == (unsigned short)-1 ) {
    creature->send( "You can't make a link in that direction." );
    return false;
  }
  to_dir = Exit::inverse(in_dir);
  // Make sure that exit doesn't already exist...
  if ( in->exit( in_dir ) != NULL ) {
    creature->send( "There is already a %s exit here.", Exit::name(in_dir) );
    return false;
  }
  // Make sure the target room exists...
  if ( ( to = World::Instance().findRoom( estring(pieces[1]) ) ) == NULL ) {
    creature->send( "That room doesn't exist." );
    return false;
  }
  // Check permissions...
  if ( !World::Instance().hasPermission( to->area(), (Avatar*)creature ) ) {
    creature->send( "You don't have permission to edit the target room." );
    return false;
  }
  // Make sure the corresponding exit in the target room doesn't already exist...
  if ( to->exit( to_dir ) != NULL ) {
    creature->send( "Room %lu already has an exit to the %s.", to->vnum(), Exit::name(to_dir) );
    return false;
  }

  in->exit( in_dir, new Exit( in, to, in_dir ) );
  to->exit( to_dir, new Exit( to, in, to_dir ) );
  creature->send( "Exits created successfully.\n" );

  return true;
}

RCmdName::RCmdName( void ) {
  name( "name" );
  level( BUILDER );
  return;
}

bool RCmdName::execute( Creature* creature, const std::string& args ) {
  creature->room()->name( Regex::trim(args) );
  creature->send( "You've set room %lu's name to \"{W%s{x\".", creature->room()->vnum(), creature->room()->name().c_str() );
  return true;
}

RCmdSmell::RCmdSmell( void ) {
  name( "smell" );
  syntax( "syntax: smell <text>" );
  return;
}

bool RCmdSmell::execute( Creature* creature, const std::string& args ) {
  creature->room()->smell( args );
  creature->send( "Room smell set to: {y%s{x", args.c_str() );
  return true;
}

RCmdSound::RCmdSound( void ) {
  name( "sound" );
  syntax( "syntax: sound <text>" );
  return;
}

bool RCmdSound::execute( Creature* creature, const std::string& args ) {
  creature->room()->sound( args );
  creature->send( "Room sound set to: {y%s{x", args.c_str() );
  return true;
}

RCmdTerrain::RCmdTerrain( void ) {
  name( "terrain" );
  level( BUILDER );
  syntax( "syntax: terrain\n        terrain <type>" );
  return;
}

bool RCmdTerrain::execute( Creature* creature, const std::string& args ) {
  std::vector<std::string> pieces = Regex::split( args, 1 );

  if ( args.empty() ) {
    creature->send( "Currently supported terrains:\n%s", TerrainTable::Instance().list().c_str() );
    return true;
  }

  if ( pieces.size() == 1 ) {
    creature->room()->terrain( TerrainTable::Instance().find( pieces[0] ) );
    creature->send( "Room terrain set to {%c%s{x.", creature->room()->terrain()->title(), creature->room()->terrain()->name().c_str() );
  } else {
    creature->send( syntax() );
    return false;
  }

  return true;
}

RCmdUnlink::RCmdUnlink( void ) {
  name( "unlink" );
  level( BUILDER );
  syntax( "syntax: unlink <direction>" );
  return;
}

bool RCmdUnlink::execute( Creature* creature, const std::string& args ) {
  unsigned short direction = Exit::string2dir(Regex::trim(args));
  unsigned short inverse = Exit::inverse( direction );
  Room* other = NULL;
  Exit* exit = NULL;
  Exit* exit2 = NULL;

  if ( args.empty() ) {
    creature->send( syntax() );
    return false;
  }

  if ( ( exit = creature->room()->exit( direction ) ) == NULL ) {
    creature->send( "There is no exit that way." );
    return false;
  }

  // Delete the exit's counterpart first, if it has one...
  other = creature->room()->exit( direction )->target();
  if ( ( exit2 = other->exit( inverse ) ) != NULL ) {
    exit2->destroy();
    other->exit( inverse, NULL );
  }

  // Delete the exit...
  exit->destroy();
  creature->room()->exit( direction, NULL );

  creature->send( "Link removed." );
  return true;
}

